package com.framework.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.framework.dao.FlowTaskDao;
import com.framework.entity.flow.FlowTask;
import com.framework.entity.sys.*;
import com.framework.exception.RRException;
import com.framework.exception.menu.RespCode;
import com.framework.page.PageUtils;
import com.framework.redis.util.RedisUtil;
import com.framework.service.*;
import com.framework.utils.DateUtils;
import com.framework.utils.excel.ExcelUtil;
import com.framework.utils.jiufu.StringUtils;
import com.framework.utils.pay.yunzhanghujiesuan.YunJieSuanPay;
import com.framework.utils.verified.MathUtils;
import com.framework.validator.Assert;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wq
 */
@Service("flowTaskService")
public class FlowTaskServiceImpl extends ServiceImpl<FlowTaskDao, FlowTask> implements FlowTaskService {

    @Autowired
    private AgentService agentService;
    @Autowired
    private AgentInfoService agentInfoService;

    @Autowired
    private DictService dictService;

    @Autowired
    private BankService bankService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private RedisUtil redisUtil;


    @Override
    public List<FlowTask> queryFlowTaskList(String token, FlowTask flowTask, Integer pageNo) {
        if (pageNo == null) {
            throw new RRException(RespCode.NOT_PARAM_ERROR);
        }
        pageNo = pageNo * 10;
        SysAgent agent = agentService.queryAgentByToken(token);
        Long agentId = agent.getAgentId();
        flowTask.setAgentId(agentId);
        return baseMapper.queryFlowTaskList(flowTask, pageNo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertFlowTask(FlowTask flowTask) {
        flowTask.setCreateTime(new Date());
        baseMapper.insert(flowTask);
    }

    @Override
    public FlowTask queryFlowTaskByNo(String taskNo) {
        Assert.isBlank(taskNo, "参数不能为空");
        FlowTask flowTask = new FlowTask();
        flowTask.setTakeNo(taskNo);
        return baseMapper.selectOne(flowTask);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateStateByNo(String taskNo, String state, String explain) {
        if (StringUtils.isBlank(taskNo) ||
                StringUtils.isBlank(state) ||
                StringUtils.isBlank(explain)) {
            throw new RRException(RespCode.NOT_PARAM_ERROR);
        }
        baseMapper.updateStateByNo(taskNo, state, explain);
    }


    @Override
    public PageUtils queryFlowTaskListForAdmin(Map<String, Object> params) {
        if ("".equals(params.get("startTime"))) {
            params.put("startTime", null);
        }
        if ("".equals(params.get("endTime"))) {
            params.put("endTime", null);
        }
        Integer pageSize = Integer.valueOf(params.get("limit").toString());
        Integer currpage = Integer.valueOf(params.get("page").toString());
        Long deptId=Long.valueOf(params.get("deptId").toString());

        params.put("start", (currpage - 1) * pageSize);
        params.put("limit", pageSize);
        List<Map<String, Object>> list = baseMapper.queryFlowTaskListForAdmin(params);

        for (Map<String, Object> map : list) {
            Integer takeType = Integer.valueOf(map.get("takeType").toString());
            Integer waitCommit = Integer.valueOf(map.get("waitCommit").toString());
            SysDict dict = dictService.querySysDict(takeType.toString(), "take_type");
            map.put("takeType", dict.getValue());
            if (waitCommit.intValue() == 0 && deptId.equals(1L)) {
                map.put("explains", "订单挂起");
            }
        }

        Integer totalCount = baseMapper.queryFlowTaskCountForAdmin(params);

        redisUtil.set("takeDown", params, 5 * 60);
        return new PageUtils(list, totalCount, pageSize, currpage);
    }

    @Override
    public List<Map<String, Object>> countFlowTake(Map<String, Object> params) {
        if ("".equals(params.get("startTime"))) {
            params.put("startTime", null);
        }
        if ("".equals(params.get("endTime"))) {
            params.put("endTime", null);
        }
        Long deptId = Long.valueOf(params.get("deptId").toString());

        params.put("start", null);
        params.put("limit", null);
        List<Map<String, Object>> list = baseMapper.queryFlowTaskListForAdmin(params);
        BigDecimal currTakeSum = list.stream().map(e -> new BigDecimal(e.get("takeAmount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal realAmount = list.stream().map(e -> new BigDecimal(e.get("actAccountAmount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

        // 查询提现总计 success 成功， curmonth 本月 curweek 本周 yesterday 昨天
        BigDecimal totalTakeCurMon = baseMapper.queryTotalTake("success", "curmonth", deptId);
        BigDecimal totalTakeCurWeek = baseMapper.queryTotalTake("success", "curweek", deptId);
        BigDecimal totalTakeCurYesterday = baseMapper.queryTotalTake("success", "yesterday", deptId);
        Map<String, Object> takeSum = agentInfoService.queryTakeSum(deptId);

        Map<String, Object> result = new HashMap<>();
        result.put("currTakeSum", currTakeSum.toString());
        result.put("totalTakeCurMon", totalTakeCurMon);
        result.put("totalTakeCurWeek", totalTakeCurWeek);
        result.put("totalTakeCurYesterday", totalTakeCurYesterday);
        result.put("realAmount", MathUtils.formatToNumber(realAmount));
        result.put("takeSum", takeSum);
        List<Map<String, Object>> resultList = new ArrayList<>();
        resultList.add(result);
        return resultList;
    }

    @Override
    public List<String> queryExamineTake(long deptId, Integer takeType) {
        List<FlowTask> list = queryExamineTakeList(deptId, takeType);
        return list.stream().map(FlowTask::getTakeNo).collect(Collectors.toList());
    }

    @Override
    public List<FlowTask> queryExamineTakeList(long deptId, Integer takeType) {
        return selectList(new EntityWrapper<FlowTask>().eq("dept_id",deptId).eq("take_type",takeType).eq("task_state","EXAMINE"));
    }

    @Override
    public List<FlowTask> queryTakeList(String token, Integer pageNo) {
        SysAgent agent = agentService.queryAgentByToken(token);
        List<FlowTask> list = baseMapper.queryTakePageByAgentId(agent.getAgentId(), (pageNo - 1) * 10);
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String commitTake(Long[] ids) {

        List<FlowTask> tasks = selectList(new EntityWrapper<FlowTask>().in("take_id", ids));

        String success = "";
        String failure = "";

        for (FlowTask task : tasks) {
            synchronized (task) {
                Long agentId = task.getAgentId();
                System.out.println(task.getTaskState());

                if (task.getHasCommit().intValue() == 1) {
                    success += task.getTakeId();
                    continue;
                }

                if(task.getTaskState().equalsIgnoreCase("FAILURE")){
                        continue;
                }

                SysBank bank = bankService.queryBankByAgentId(agentId);
                if (bank == null) {
                    task.setTaskState("FAILURE");
                    task.setExplains("提现失败--未查询到银行卡");
                    task.setHasCommit(1);
                    updateById(task);
                    agentInfoService.addBalance(agentId, task.getTakeAmount());
                    failure += task.getTakeId();
                    continue;
                }
                SysAgentInfo infoById = agentInfoService.getAgentInfoById(agentId);

                if (infoById == null) {
                    task.setTaskState("FAILURE");
                    task.setExplains("提现失败--未查询到详细信息");
                    task.setHasCommit(1);
                    updateById(task);
                    agentInfoService.addBalance(agentId, task.getTakeAmount());
                    failure += task.getTakeId();
                    continue;
                }

                if (StringUtils.isNull(infoById.getIdCard())) {
                    task.setTaskState("FAILURE");
                    task.setExplains("提现失败--未查询到身份证信息");
                    task.setHasCommit(1);
                    updateById(task);
                    agentInfoService.addBalance(agentId, task.getTakeAmount());
                    failure += task.getTakeId();
                    continue;
                }

                SysPayment sysPayment = paymentService.selectOne(new EntityWrapper<SysPayment>().eq("dept_id", bank.getDeptId()).eq("pay_type", task.getTakeType()));
                if (sysPayment == null) {
                    task.setTaskState("FAILURE");
                    task.setExplains("提现失败--未查询到代付配置信息");
                    task.setHasCommit(1);
                    updateById(task);
                    agentInfoService.addBalance(agentId, task.getTakeAmount());
                    failure += task.getTakeId();
                    continue;
                }

                YunJieSuanPay.yunJieSuanPay(task.getTakeNo(), bank, infoById.getIdCard(), String.valueOf(task.getActAccountAmount()), sysPayment, sysPayment.getPayName());

                task.setHasCommit(1);
                updateById(task);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }

        String result = "操作成功!";
        if (success.length() > 0) {
            result += "以下id的提现记录已处理:" + success + "\n";
        }
        if (failure.length() > 0) {
            result += "以下提现记录提交失败:" + failure;
        }

        return result;

    }

    @Override
    public void downLoadExcel(Long deptId, HttpServletResponse response) {
        Map<String, Object> params;
        if (redisUtil.hasKey("takeDown")) {
            params = (Map<String, Object>) redisUtil.get("takeDown");
            params.remove("limit");
            params.remove("start");
        } else {
            params = new HashMap<>(1);
            params.put("deptId", deptId);
        }

        List<Map<String, Object>> list = baseMapper.queryFlowTaskListForAdmin(params);

        for (Map<String, Object> map : list) {
            Integer takeType = Integer.valueOf(map.get("takeType").toString());
            Integer waitCommit = Integer.valueOf(map.get("waitCommit").toString());
            SysDict dict = dictService.querySysDict(takeType.toString(), "take_type");
            map.put("takeType", dict.getValue());
            if (waitCommit.intValue() == 0 && deptId.equals(1L)) {
                map.put("explains", "订单挂起");
            }
        }

        String path;


        if(params.get("startTime")!=null && params.get("endTime")!=null){
            String startTime=params.get("startTime").toString();
            String endTime=params.get("endTime").toString();
            if(startTime.equals(endTime)){
                path=startTime;
            }else {
                path=startTime+"_"+endTime;
            }
        }else {
            path=DateUtils.format(new Date(),DateUtils.DATE_PATTERN);
        }

        String fileName="提现明细表_"+ path +".xlsx";
        String [] titles={"提现流水号","提现时间","提现金额","手续费","实际到账","提现结果","提现方式","提现人","联系方式","实时余额","提现后余额"};
        String sheetName = "明细";
        String [][] content=new String[list.size()][];

        for (int i = 0; i < list.size(); i++) {
            content[i] = new String[titles.length];
            Map<String, Object> obj = list.get(i);
            //提现流水号
            content[i][0] = obj.get("takeNo").toString();
            content[i][1] = obj.get("createTime").toString();
            content[i][2] = obj.get("takeAmount").toString();
            content[i][3] = obj.get("serviceAmount").toString();
            content[i][4] = obj.get("actAccountAmount").toString();
            content[i][5] = obj.get("explains").toString();
            content[i][6] = obj.get("takeType").toString();
            content[i][7] = obj.get("name").toString();
            content[i][8] = obj.get("phone").toString();
            content[i][9] = obj.get("currentAmount").toString();
            content[i][10] = obj.get("afterAmount").toString();

        }
        Workbook workbook = ExcelUtil.generateNewWorkbook(sheetName,titles,content);
        ExcelUtil.downLoadByExcel(response, fileName, workbook);
    }

}
